package com.ibiz.znjd.baidu.location;

import com.baidu.location.BDAbstractLocationListener;
import com.baidu.location.BDLocation;
import com.baidu.location.LocationClient;
import com.baidu.location.LocationClientOption;
import com.baidu.location.LocationClientOption.LocationMode;
import com.getcapacitor.JSObject;
import com.ibiz.znjd.MainActivity;
import com.karumi.dexter.Dexter;
import com.karumi.dexter.listener.multi.CompositeMultiplePermissionsListener;

import android.Manifest;
import android.annotation.TargetApi;
import android.app.Notification;
import android.content.Context;
import android.os.Build;
import android.os.SystemClock;
import android.webkit.WebView;

import java.util.HashSet;
import java.util.Set;

/**
 * 定位服务LocationClient 相关
 *
 * @author baidu
 */
public class LocationService {
    /**
     *  定位client
     */
    private LocationClient client = null;

    /**
     * 默认配置
     */
    private static LocationClientOption mOption;

    /**
     * 实际使用的配置
     */
    private static LocationClientOption  DIYoption;

    /**
     * 同步锁对象
     */
    private Object objLock;

    /**
     * 定位信息JS对象
     */
    public JSObject locationObj;

    /**
     * 监听者集合
     */
    public Set<LocationServiceListener> listeners = new HashSet<>();

    /**
     * 后台定位用的通知
     */
    private Notification mNotification;

    /**
     * 定位结果回调，重写onReceiveLocation方法，可以直接拷贝如下代码到自己工程中修改
     */
    private BDAbstractLocationListener mListener = new BDAbstractLocationListener() {

        /**
         * 定位请求回调函数
         * @param location 定位结果
         */
        @Override
        public void onReceiveLocation(BDLocation location) {
            System.out.println("定位回调: "+ SystemClock.elapsedRealtime());
            locationObj = LocationUtils.turnToJson(location);
            for(LocationServiceListener listener : listeners){
                listener.onReceiveLocation(location, locationObj);
            }
        }
    };

    /***
     * 初始化 LocationClient
     *
     * @param locationContext
     */
    public LocationService(Context locationContext) {
        objLock = new Object();
        synchronized (objLock) {
            if (client == null) {
                try {
                    client = new LocationClient(locationContext);
                    client.registerLocationListener(mListener);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (client != null) {
                client.setLocOption(getDefaultLocationClientOption());
            }
        }
    }

    /**
     * Android 从6.0 开始要求一些权限在动态运行时申请
     * 单纯的在 AndroidManifest.xml 注册不起作用
     */
    @TargetApi(23)
    public static void getPermissions(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            String BACKGROUND_LOCATION_PERMISSION = "android.permission.ACCESS_BACKGROUND_LOCATION";
            Dexter.withContext(context)
                .withPermissions(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION,BACKGROUND_LOCATION_PERMISSION)
                .withListener(new CompositeMultiplePermissionsListener())
                .check();
        }
    }

    /***
     * 注册定位监听
     *
     * @param listener
     * @return
     */

    public boolean registerListener(LocationServiceListener listener) {
        boolean isSuccess = false;
        if ((client != null) && (listener != null) && !listeners.contains(listener)) {
            listeners.add(listener);
            isSuccess = true;
        }
        return isSuccess;
    }

    /**
     * 删除监听
     * @param listener
     */
    public void unregisterListener(LocationServiceListener listener) {
        if ((client != null) && (listener != null) && listeners.contains(listener)) {
            listeners.remove(listener);
        }
    }

    /**
     * @return 获取sdk版本
     */
    public String getSDKVersion() {
        if (client != null) {
            String version = client.getVersion();
            return version;
        }
        return null;
    }

    /***
     * 设置定位参数
     *
     * @param option
     * @return isSuccessSetOption
     */
    public boolean setLocationOption(LocationClientOption option) {
        boolean isSuccess = false;
        if ((client != null) && (option != null)) {
            if (client.isStarted()) {
                client.stop();
            }
            DIYoption = option;
            client.setLocOption(option);
        }
        return isSuccess;
    }

    /**
     * 开发者应用如果有H5页面使用了百度JS接口，该接口可以辅助百度JS更好的进行定位
     *
     * @param webView 传入webView控件
     */
    public void enableAssistanLocation(WebView webView) {
        if (client != null) {
            client.enableAssistantLocation(webView);
        }
    }

    /**
     * 停止H5辅助定位
     */
    public void disableAssistantLocation() {
        if (client != null) {
            client.disableAssistantLocation();
        }
    }

    /***
     *
     * @return DefaultLocationClientOption  默认O设置
     */
    public LocationClientOption getDefaultLocationClientOption() {
        if (mOption == null) {
            mOption = new LocationClientOption();
            mOption.setCoorType( "bd09ll" ); // 可选，默认gcj02，设置返回的定位结果坐标系，如果配合百度地图使用，建议设置为bd09ll;
            mOption.setScanSpan(3000); // 可选，默认0，即仅定位一次，设置发起连续定位请求的间隔需要大于等于1000ms才是有效的
            mOption.setIsNeedAddress(true); // 可选，设置是否需要地址信息，默认不需要
            mOption.setIsNeedLocationDescribe(true); // 可选，设置是否需要地址描述
            mOption.setNeedDeviceDirect(false); // 可选，设置是否需要设备方向结果
            mOption.setLocationNotify(false); // 可选，默认false，设置是否当gps有效时按照1S1次频率输出GPS结果
            mOption.setIgnoreKillProcess(true); // 可选，默认true，定位SDK内部是一个SERVICE，并放到了独立进程，设置是否在stop
            mOption.setIsNeedLocationDescribe(true); // 可选，默认false，设置是否需要位置语义化结果，可以在BDLocation
            mOption.setIsNeedLocationPoiList(true); // 可选，默认false，设置是否需要POI结果，可以在BDLocationf
            mOption.SetIgnoreCacheException(false); // 可选，默认false，设置是否收集CRASH信息，默认收集
            mOption.setLocationMode(LocationMode.Hight_Accuracy); // 可选，默认高精度，设置定位模式，高精度，低功耗，仅设备，模糊
            mOption.setIsNeedAltitude(false); // 可选，默认false，设置定位时是否需要海拔信息，默认不需要，除基础定位版本都可用
            // 可选，设置首次定位时选择定位速度优先还是定位准确性优先，默认为速度优先
            mOption.setFirstLocType(LocationClientOption.FirstLocType.SPEED_IN_FIRST_LOC);
            mOption.setOpenGps(true); // 可选，默认false，设置是否开启Gps定位
        }
        return mOption;
    }


    /**
     * @return DIYOption 自定义Option设置
     */
    public LocationClientOption getOption() {
        if (DIYoption == null) {
            DIYoption = new LocationClientOption();
        }
        return DIYoption;
    }

    public void start(Context context) {
        synchronized (objLock) {
            if (client != null && !client.isStarted()) {
                // 将定位SDK的SERVICE设置成为前台服务, 提高定位进程存活率
//                this.initNotification(context);
//                client.enableLocInForeground(1, mNotification);
                client.start();
            }
        }
    }

    /**
     * 初始化前台服务
     */
    private void initNotification (Context context) {
        //设置后台定位
        NotificationUtils notificationUtils = ((MainActivity)context).notificationUtils == null ? new NotificationUtils(context) : ((MainActivity)context).notificationUtils;
        Notification.Builder builder = notificationUtils.getAndroidChannelNotification("移动监督保活通知", "正在后台定位");
        mNotification = builder.setWhen(System.currentTimeMillis()).build(); // 获取构建好的Notification
        mNotification.defaults = Notification.DEFAULT_SOUND; //设置为默认的声音
    }

    public void requestLocation() {
        if (client != null) {
            client.requestLocation();
        }
    }

    public void stop() {
        synchronized (objLock) {
            if (client != null && client.isStarted()) {
                // 关闭前台定位服务
//                client.disableLocInForeground(true);
                // 取消之前注册的 BDAbstractLocationListener 定位监听函数
                client.unRegisterLocationListener(mListener);
                client.stop();
            }
        }
    }

    public boolean isStart() {
        if (client == null) {
            return false;
        }
        return client.isStarted();
    }

    public boolean requestHotSpotState() {
        if (client == null) {
            return false;
        }
        return client.requestHotSpotState();
    }
}